<!-- 商品列表 -->
<template>
  <el-container>
    <el-header>
      <div style="padding-left: 10px;">
        <el-checkbox :value="allChecked" :indeterminate="indeterminate" @change="checkedChange">全选本页</el-checkbox>
        <el-dropdown @command="productCommand">
          <el-button icon="el-icon-more" circle size="mini"></el-button>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="up">批量上架</el-dropdown-item>
            <el-dropdown-item command="down">批量下架</el-dropdown-item>
            <el-dropdown-item command="delete">批量删除</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
      <div class="cat">
        <el-radio-group v-model="catRadio" size="small" @change="catChange">
          <el-radio-button label="全部"></el-radio-button>
          <el-radio-button label="只看上架"></el-radio-button>
          <el-radio-button label="只看下架"></el-radio-button>
        </el-radio-group>

        <el-input placeholder="名称搜索" clearable v-model="searchContent">
          <template slot="append">
            <i class="el-icon-search"></i>
          </template>
        </el-input>

        <el-button icon="el-icon-plus" type="primary" @click="add">新增商品</el-button>
      </div>
    </el-header>

    <el-main>
      <p v-if="list.length === 0" style="font-size: 2em; font-weight: 800;">无任何商品！</p>
      <ul class="product-list" v-else>
        <li v-for="product in list" :key="product.id" :class="{ 'down': product.status === 2}">
          <el-checkbox v-model="product.checked"></el-checkbox>
          <el-avatar shape="square" :size="130" fit="fill" :src="product.logo | big"></el-avatar>
          <ul class="base">
            <li class="name">{{product.name}}</li>
            <li class="price">
              价格:
              <span class="c1">￥{{product.price}}</span>
              库存:
              <span class="c2">{{product.stock | displayStock}}</span>
            </li>
            <li class="format">规格描述：{{product.description}}</li>
            <li class="other">
              SKU:
              <span>{{product.sku}}</span>UPC：
              <span>{{product.upc}}</span>
            </li>
          </ul>
          <div class="business">
            <table>
              <tr v-for="attr in product.attributes" :key="attr.id">
                <td>{{attr.title}}：</td>
                <td>{{attr.desc}}</td>
              </tr>
            </table>
          </div>
          <div class="operation">
            <el-button type="primary" v-if="product.status === 1" plain @click="down(product)">下架</el-button>
            <el-button type="default" v-else plain @click="up(product)">上架</el-button>
            <div class="edit">
              <el-link icon="el-icon-edit" @click="edit(product)" type="primary">编辑</el-link>
              <el-link icon="el-icon-remove" type="warning" @click="deleteProduct(product)">删除</el-link>
            </div>
          </div>
        </li>
      </ul>
    </el-main>
    <el-footer>
      <el-pagination background layout="prev, pager, next" :page-size="paging.pageSize" :total="paging.count" @current-change="go"></el-pagination>
    </el-footer>

    <el-dialog
      title="新增商品"
      :visible.sync="dialogVisible"
      @closed="dialogClose"
      @opened="dialogOpen"
      width="50%"
      center
      :close-on-click-modal="false"
    >
      <el-form ref="form" :model="form" :rules="formRules" label-width="140px">
        <el-form-item label="商品图片">
          <el-upload action="#" list-type="picture-card" ref="imageCom" :auto-upload="false">
            <i slot="default" class="el-icon-plus"></i>
            <div slot="file" slot-scope="{file}">
              <img class="el-upload-list__item-thumbnail" :src="file.url" alt />
              <span class="el-upload-list__item-actions">
                <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
                  <i class="el-icon-zoom-in"></i>
                </span>
                <span class="el-upload-list__item-delete" @click="handleRemove(file)">
                  <i class="el-icon-delete"></i>
                </span>
              </span>
            </div>
          </el-upload>
        </el-form-item>
        <el-form-item label="所属分类">
          <el-select v-model="form.productTypeId" placeholder="请选择分类" @change="changeType">
            <el-option
              v-for="item in productTypes"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="商品名称" prop="name">
          <el-input v-model.trim="form.name"></el-input>
        </el-form-item>
        <el-form-item label="商品编码">
          <el-input v-model.trim="form.code" placeholder="不输入则系统自动生成" :disabled="form.id > 0"></el-input>
        </el-form-item>
        <el-form-item label="规格描述">
          <el-input v-model.trim="form.description"></el-input>
        </el-form-item>
        <el-form-item label="单位">
          <el-autocomplete
            class="inline-input"
            v-model="form.unitName"
            :fetch-suggestions="unitSearch"
          ></el-autocomplete>
        </el-form-item>
        <el-form-item label="价格" prop="price">
          <el-input v-model="form.price" type="number"></el-input>
        </el-form-item>
        <el-form-item label="库存" prop="stock">
          <el-input v-model="form.stock" type="number"></el-input>
          <label style="font-size: .9em;color: gray;margin-left: 5px;">-1 表示无限制</label>
        </el-form-item>
        <el-form-item label="是否参与订单折扣">
          <el-switch v-model="form.isDiscount"></el-switch>
        </el-form-item>
        <el-form-item label="UPC码">
          <el-input v-model.trim="form.upc"></el-input>
        </el-form-item>
        <el-form-item label="SKU码">
          <el-input v-model.trim="form.sku"></el-input>
        </el-form-item>
        <el-form-item label="排序码" prop="sort">
          <el-input v-model="form.sort" type="number"></el-input>
        </el-form-item>
        <el-form-item label="业务属性">
          <div class="attrs">
            <div class="attr-container">
              <p class="attr-item" v-for="(item, index) in form.attributes" :key="index">
                <el-input v-model.trim="item.title" ref="attr_title"></el-input>
                <span>-</span>
                <el-input v-model.trim="item.desc"></el-input>
              </p>
            </div>
            <el-button @click="addAttr" style="margin-left: 5px;">
              <i class="el-icon-plus"></i>
            </el-button>
            <el-button @click="delAttr">
              <i class="el-icon-minus"></i>
            </el-button>
          </div>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveProduct">保 存</el-button>
      </span>
    </el-dialog>

    <el-dialog :visible.sync="imageDialogVisible">
      <img width="100%" :src="dialogImageUrl" alt />
    </el-dialog>
  </el-container>
</template>

<script>
import { deepClone, getArrIndex } from '@/lib/util'
import { getMax, imageCompress, throttle } from '@/lib/tools'
import {
  getProducts,
  getMaxSort,
  createProduct,
  updateProduct,
  deleteProduct,
  up,
  down,
  deleteBatch,
  upBatch,
  downBatch,
} from '@/api/product'
import { mapState } from 'vuex'
import { big } from '@/filters/app'
const paging = { pageIndex: 1, pageSize: 2, count: 0 }
const formTemplate = {
  id: 0,
  name: '',
  code: '',
  description: '',
  unitName: '',
  isDiscount: true,
  price: 0,
  stock: -1,
  upc: '',
  sku: '',
  logo: '',
  sort: 0,
  productTypeId: '',
  images: [],
  attributes: [{ title: '', desc: '' }],
}
export default {
  name: 'productList',
  components: {},
  props: {
    typeId: {
      type: Number,
      default: 0,
    },
    productTypes: {
      type: Array,
      default: [],
    },
  },
  watch: {
    typeId() {
      this.paging = Object.assign({}, paging)
      this.loadList()
    },
    searchContent() {
      throttle(this.loadList, this)
    },
  },
  computed: {
    ...mapState(['units']),
    catStatus() {
      // 列表商品状态（上架/下架）
      if (this.catRadio === '只看上架') return 1
      else if (this.catRadio === '只看下架') return 2
      else return 99
    },
    allChecked() {
      // 是否本页全选
      let checkedCount = this.list.filter((a) => a.checked).length
      return checkedCount > 0 && checkedCount === this.list.length
    },
    indeterminate() {
      // 未全部选中
      let checkedCount = this.list.filter((a) => a.checked).length
      return checkedCount > 0 && checkedCount < this.list.length
    }
  },
  data() {
    return {
      list: [], // 商品列表
      paging: {
        ...paging
      },
      catRadio: '全部', // 选择的商品状态
      searchContent: '', // 搜索关键字
      dialogVisible: false, // 新增对话框是否隐藏
      imageDialogVisible: false, // 查看图片对话框
      dialogImageUrl: '', //
      form: {},
      formRules: {
        name: [{ required: true, message: '请输入商品名称', trigger: 'blur' }],
        price: [{ required: true, message: '请输入价格', trigger: 'blur' }],
      },
    }
  },
  //方法集合
  methods: {
    // 加载产品列表
    async loadList() {
      let { data } = await getProducts(
        this.typeId,
        this.catStatus,
        this.searchContent,
        this.paging
      )
      data.list.forEach((a) => {
        a.checked = false
        a.attributes = a.attributes ? JSON.parse(a.attributes) : []
      })
      this.list = data.list
      this.paging.count = data.count
    },
    // 商品批量命令
    productCommand(e) {
      let products = this.list.filter((a) => a.checked)
      if (products.length === 0) {
        this.$message({
          type: 'error',
          message: '请先选择商品',
        })
        return
      }
      if (e === 'up') {
        this.upBatch(products)
      } else if (e === 'down') {
        this.downBatch(products)
      } else if (e === 'delete') {
        this.deleteBatch(products)
      }
    },
    // 查看不同商品状态
    async catChange(e) {
      await this.loadList()
    },
    // 新增商品
    add() {
      this.dialogVisible = true
      this.form = deepClone(formTemplate)

      this.$nextTick(() => {
        this.$refs['imageCom'].uploadFiles = []
      })
    },
    // 编辑商品
    edit(product) {
      this.dialogVisible = true
      this.form = deepClone(product)
      this.$nextTick(() => {
        let images = this.form.images || []
        this.$refs['imageCom'].uploadFiles = images.map((image) => ({
          name: image.name,
          id: image.id,
          uid: image.id,
          url: big(image.name),
        }))
      })
    },
    // 更改商品类型时，读取最大的商品排序
    async changeType(e) {
      let max = await getMaxSort(e)
      this.form.sort = max + 1
    },
    // 单位搜索
    unitSearch(a, cb) {
      return cb(this.units)
    },
    // 增加业务属性
    addAttr() {
      this.form.attributes.push({ title: '', desc: '' })
      this.$nextTick(() => {
        this.$refs['attr_title'][this.$refs['attr_title'].length - 1].focus()
      })
    },
    // 删除业务属性
    delAttr() {
      this.form.attributes.pop()
    },
    // 查看图片
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.imageDialogVisible = true
    },
    // 删除图片
    handleRemove(file) {
      let index = this.$refs['imageCom'].uploadFiles.indexOf(file)
      this.$refs['imageCom'].uploadFiles.splice(index, 1)
    },
    // 保存商品
    saveProduct() {
      this.$refs['form'].validate(async (valid) => {
        if (!valid) {
          this.$message.error('请将表单输入完整')
          return
        }
        if (!this.form.productTypeId) {
          let result = await this.$confirm(
            '未选择商品类型，仍然保存吗？',
            '提示'
          ).catch(() => {})
          if (!result) return
        }
        let isCancel = false
        this.form.attributes.some((item) => {
          if (!item.title || !item.desc) {
            this.$message.error('请将业务属性输入完整！')
            isCancel = true
          }
          return isCancel
        })

        let files = this.$refs['imageCom'].uploadFiles || []
        this.form.images = []
        files.forEach((file) => {
          let big, small
          if (!file.id) {
            big = imageCompress(file.url, 600)
            small = imageCompress(file.url, 150)
          }
          this.form.images.push({
            id: file.id,
            name: file.name,
            big,
            small,
          })
        })

        if (isCancel) return
        let loading = this.$$loading()
        let isModify = this.form.id > 0
        let body = { ...this.form, attributes: JSON.stringify(this.form.attributes) }
        if (isModify) {
          var { data } = await updateProduct(body)
        } else {
          var { data } = await createProduct(body)
        }
        data.checked = false
        data.attributes = data.attributes ? JSON.parse(data.attributes) : []
        this.$notify({
          title: '提示',
          message: '保存成功',
          type: 'success',
        })
        this.dialogVisible = false
        if (isModify) {
          let index = 0
          this.list.some((a, b) => {
            if (a.id !== this.form.id) return false
            index = b
            return true
          })
          this.list.splice(index, 1, data)
        } else {
          this.list.unshift(data)
        }
        loading.close()
      })
    },
    // 关闭商品框
    dialogClose(e) {
      this.form.images = []
      this.$refs['imageCom'].clearFiles()
    },
    // 打开商品狂
    dialogOpen() {
      this.$refs['form'].$el.scrollTop = 0
      this.$refs['form'].clearValidate()
    },
    // 删除商品
    deleteProduct(product) {
      this.$confirm(`确认删除商品【${product.name}】吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(async () => {
          let res = await deleteProduct(product.id)
          this.list.splice(getArrIndex(this.list, product), 1)
          this.$message({
            type: 'success',
            message: res.message,
          })
        })
        .catch(() => {})
    },
    // 上架商品
    async up(product) {
      let res = await up(product.id)
      product.status = 1
      this.$message({
        type: 'success',
        message: res.data,
      })
    },
    // 下架商品
    async down(product) {
      let res = await down(product.id)
      product.status = 2
      this.$message({
        type: 'success',
        message: res.data,
      })
    },
    // 更改全选
    checkedChange() {
      let checked = this.allChecked
      this.list.forEach((a) => (a.checked = !checked))
    },
    // 批量上架
    async upBatch(products) {
      let ids = products.map((a) => a.id)
      let res = await upBatch(ids)
      products.forEach((a) => (a.status = 1))
      this.$message({
        type: 'success',
        message: res.data,
      })
    },
    // 批量下架
    async downBatch(products) {
      let ids = products.map((a) => a.id)
      let res = await downBatch(ids)
      products.forEach((a) => (a.status = 2))
      this.$message({
        type: 'success',
        message: res.data,
      })
    },
    // 批量删除
    async deleteBatch(products) {
      this.$confirm(`确认删除商品吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(async () => {
          let ids = products.map((a) => a.id)
          let res = await deleteBatch(ids)
          products.forEach((product) => {
            this.list.splice(getArrIndex(this.list, product), 1)
          })
          this.$message({
            type: 'success',
            message: res.data,
          })
        })
        .catch(() => {})
    },
    async go(e) {
      this.paging.pageIndex = e
      await this.loadList()
    }
  },
  async created() {
    await this.loadList()
  },
}
</script>
<style lang='scss' scoped>
.el-container {
  border: 1px solid #ddd;
  border-left: none;
}
.el-header {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  align-items: center;
  padding: 0;
  border-bottom: 1px solid #ddd;

  .el-button {
    margin-left: 20px;
  }

  .cat {
    display: flex;
    flex-flow: row wrap;
    justify-content: flex-end;
    align-items: center;
    margin-right: 10px;
    flex-grow: 1;

    .el-radio-group {
      margin-right: 10px;
    }

    .el-input {
      width: 200px;
    }
  }
}

.el-main {
  padding: 0;
}
.el-form {
  min-height: 400px;
  max-height: 600px;
  overflow: auto;
  padding-right: 10px;

  .el-input {
    width: 350px;
  }

  .attrs {
    display: flex;
    flex-flow: row nowrap;
    justify-content: flex-start;
    align-items: flex-start;

    .attr-container {
      width: 350px;
    }

    .attr-item {
      display: flex;
      flex-flow: row nowrap;
      justify-content: space-between;
      margin: 0;
      padding: 0;
      margin-bottom: 5px;

      .el-input {
        width: 46%;
      }
    }
  }
}

.product-list {
  list-style: none;
  padding: 0;
  margin: 0;

  > li {
    list-style: none;
    display: flex;
    flex-flow: row nowrap;
    justify-content: flex-start;
    border-bottom: 1px dashed #ccc;
    padding: 10px;
    align-items: center;

    .el-checkbox {
      margin: 0 15px;
    }

    .el-avatar {
      width: 130px;
    }

    .base {
      list-style: none;
      padding: 0;
      margin: 0;
      padding-left: 20px;
      min-width: 350px;

      li {
        text-align: left;
        padding: 5px 0;
        font-size: 0.9em;
        color: #666;
      }
      .name {
        color: #000;
        white-space: nowrap;
        font-size: 1.3em;
        font-weight: 800;
        border-bottom: 1px solid #ddd;
      }
      .price {
        color: #000;
        .c1 {
          display: inline-block;
          width: 100px;
          color: red;
        }
        .c2 {
          display: inline-block;
          color: #30b08f;
        }
      }
      .other {
        span {
          display: inline-block;
          max-width: 200px;
          min-width: 100px;
        }
      }
    }

    .business {
      padding-left: 30px;
      font-size: 0.9em;
      flex-grow: 1;
      min-height: 120px;
      td {
        padding: 5px 0;
        text-align: left;
      }
      td:first-child {
        max-width: 200px;
      }
      td:last-child {
        max-width: 220px;
      }
    }

    .operation {
      max-width: 200px;
      display: flex;
      flex-flow: column;
      justify-content: center;
      align-items: center;

      .edit {
        font-size: 0.9em;
        margin-top: 10px;

        .el-link:first-child {
          margin-right: 20px;
        }
      }
    }
  }
}

.down {
  background-color: #ededed;
}

.el-footer {
  padding-top: 10px;
}
</style>
